﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Atmk.WaterMeter.MIS.Commons.Enums;
using Atmk.WaterMeter.MIS.Commons.Interfaces;
using Atmk.WaterMeter.MIS.Commons.Interfaces.Logic.Statistics;
using Atmk.WaterMeter.MIS.Commons.Interfaces.Repository;
using Atmk.WaterMeter.MIS.Commons.Utils;
using Atmk.WaterMeter.MIS.Commons.ViewModels.Chart;
using Atmk.WaterMeter.MIS.Entities;
using Atmk.WaterMeter.MIS.Entities.Areas;
using Atmk.WaterMeter.MIS.Entities.Enums;
using Atmk.WaterMeter.MIS.Entities.Records;
using NLog;

namespace Atmk.WaterMeter.MIS.Logic.Statistics
{
    
    public class ConsumptionStatisticsLogic : BaseLogic
    {
        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
        private readonly IRepository _repository;
        private readonly IChartRepository _chartRepository;
        private readonly IDistrictRepository _districtRepository;
        private readonly IMeterReadingRepository _baseInfoLogic;
        private List<DistrictEntity> _districts;
        private List<DistrictEntity> _leafDistricts;
        private List<OwnerEntity> _owners;
        private List<AccountEntity> _accounts;
        private List<MeterEntity> _meters;
        private List<MeterReadingRecord> _meterReadings;

        public ConsumptionStatisticsLogic(
            IRepository repository,
            IDistrictRepository districtRepository,
            IChartRepository chartRepository,
            IMeterReadingRepository baseInfoLogic
        )
        {
            _repository = repository;
            _chartRepository = chartRepository;
            _districtRepository = districtRepository;
            _baseInfoLogic = baseInfoLogic;
        }

        /// <summary>
        /// 查询图表
        /// </summary>
        /// <param name="payloadId"></param>
        /// <returns></returns>
        public ChartResult GetChart(string payloadId)
        {
            SetListValue(payloadId);
            //获取必须数据的集合
            var chatResult = new ChartResult
            {
                errcode = 0,
                msg = "ok",
                datas = new ChartDatas
                {
                    statisticsInfoData = GetStatisticsInfoData(),
                    waterConsumptionInfoData = GetWaterConsumptionInfoData(),
                    costReminderData = GetCostReminderData(),
                    closingvalveData = GetClosingvalveData(),
                    districtReadRatioData = GetDistrictReadRatioData(),
                    yesterdayConsumptionData = GetYesterdayConsumptionData(),
                    lastMonthDistrictConsumptionsCountData = GetLastMonthWaterConsumptionsCountData(),
                    lastSeasonWaterConsumptionsCountData = GetLastSeasonWaterConsumptionsCountData(),
                    lastYearWaterConsumptionsCountData = GetYearWaterConsumptionsCountData(DateTime.Now.Year - 1)
                }
            };
            return chatResult;
        }
        /// <summary>
        /// 异步查询图表
        /// </summary>
        /// <param name="payloadId"></param>
        /// <returns></returns>
        public Task<ChartResult> GetChartAsync(string payloadId)
        {
            throw new NotImplementedException();
        }
        
      

        /// <summary>
        /// 获取统计信息
        /// </summary>
        /// <returns></returns>
        private StatisticsInfoData GetStatisticsInfoData()
        {
            var onlineMeters = _baseInfoLogic.RangeNewDateMeterReadingRecords(
                _meters.Select(m => m.MeterNumber).ToList(), DateTime.Now.Date.AddDays(-3), DateTime.Now.Date);
            //水表在线率：近三日抄表记录水表数量，除以总水表数量
            var result = new StatisticsInfoData
            {
                districtCount = _districts.Count,
                meterCount = _meters.Count,
                ownerCount = _owners.Count
            };
            if (onlineMeters != null)
                result.onlineRatio = onlineMeters.Count * 100.00 / _meters.Count * 100.00;
            else
                result.onlineRatio = 0.00;
            return result;
        }

        /// <summary>
        /// 总用水量统计
        /// </summary>
        /// <returns></returns>
        private WaterConsumptionInfoData GetWaterConsumptionInfoData()
        {
            //获取昨日用水量
            var lastDay = RangeMeterReadingRecord(_meterReadings, DateTime.Now.Date.AddDays(-1),
                DateTime.Now.Date.AddMilliseconds(-1)).Sum(l => l.Last().Value - l.First().LastValue);
            //本月用水量
            DateTimeHelper.GetPeriod(Period.Month, out var mBegin, out var mEnd);
            var thisMonth = RangeMeterReadingRecord(_meterReadings, mBegin, DateTime.Now.Date.AddMilliseconds(-1))
                .Sum(l => l.Last().Value - l.First().Value);

            //上月用水量记录
            DateTimeHelper.GetPeriod(Period.Month, out var mBeginDate, out var mEndDate, DateTime.Now.AddMonths(-1));
            var lastMonth = RangeMeterReadingRecord(_meterReadings, mBeginDate, mEndDate)
                .Sum(l => l.Last().Value - l.First().Value);
            //同期月用水量//TODO:如何获取暂无概念
            var r = new WaterConsumptionInfoData
            {
                yesterday = (int)lastDay,
                nowMonth = (int)thisMonth,
                lastMonth = (int)lastMonth,
                sameMonth = 0
            };
            return r;
        }

        /// <summary>
        /// 按片区获取年用水每月总量
        /// </summary>
        /// <param name="year"></param>
        /// <returns></returns>
        private YearWaterConsumptionsCountData GetYearWaterConsumptionsCountData(int year)
        {
            var r = new YearWaterConsumptionsCountData
            {
                list = new List<WaterConsumptionsCountListItem>()
            };
            foreach (var item in _districts)
            {
                var listItem = new WaterConsumptionsCountListItem
                {
                    districtId = item.Id.ToString(),
                    districtName = item.Name,
                    waterConsumptions = new List<double>(12)
                };
                for (var i = 0; i < listItem.waterConsumptions.Count; i++)
                {
                    DateTimeHelper.GetPeriod(Period.Month, out var mBeginDate, out var mEndDate,
                        new DateTime(year, i + 1, 01));
                    var meterReadings = DistrictMeterRecording(item);
                    //按片区统计指定年的每个月的用水量
                    listItem.waterConsumptions[i] = RangeMeterReadingRecord(meterReadings, mBeginDate, mEndDate)
                        .Sum(l => l.Last().Value - l.First().Value);
                }
                r.list.Add(listItem);
            }
            r.total = r.list.Count.ToString();
            return r;
        }

        /// <summary>
        /// 按片区获取上季度每月用水总量
        /// </summary>
        /// <returns></returns>
        private WaterConsumptionsCountData GetLastSeasonWaterConsumptionsCountData()
        {
            //获取上季度第一个月第一天
            var lastQuarterDate = DateTimeHelper.GetQuarter(1, false);
            var r = new WaterConsumptionsCountData
            {
                list = new List<WaterConsumptionsCountListItem>()
            };
            foreach (var item in _districts)
            {
                var listItem = new WaterConsumptionsCountListItem
                {
                    districtId = item.Id.ToString(),
                    districtName = item.Name,
                    waterConsumptions = new List<double>(3)
                };
                for (var i = 0; i < listItem.waterConsumptions.Count; i++)
                {
                    DateTimeHelper.GetPeriod(Period.Month, out var mBeginDate, out var mEndDate,
                        lastQuarterDate.AddMonths(-i));
                    var meterReadings = DistrictMeterRecording(item);
                    //按片区统计指定年/季度的每个月的用水量
                    listItem.waterConsumptions[i] = RangeMeterReadingRecord(meterReadings, mBeginDate, mEndDate)
                        .Sum(l => l.Last().Value - l.First().Value);
                }
                r.list.Add(listItem);
            }
            r.total = r.list.Count.ToString();
            return r;
        }

        /// <summary>
        /// 按片区获取上月阶梯用水总量
        /// </summary>
        /// <returns></returns>
        private WaterConsumptionsCountData GetLastMonthWaterConsumptionsCountData()
        {
            //获取阶梯用水量//TODO:没有标准
            var cutPoint1 = 15;
            var cutPoint2 = 22;
            try
            {
                var step = _repository.FindAllAsNoTracking<PriceStepEntity>()
                    .First(s => s.MeterType == MeterType.冷水水表.ToString());
                cutPoint1 = step.CutPoint1;
                cutPoint2 = step.CutPoint2;
            }
            catch (Exception e)
            {
                _logger.Error(e);
            }
            var r = new WaterConsumptionsCountData
            {
                list = new List<WaterConsumptionsCountListItem>()
            };
            foreach (var item in _districts)
            {
                var listItem = new WaterConsumptionsCountListItem
                {
                    districtId = item.Id.ToString(),
                    districtName = item.Name,
                    waterConsumptions = new List<double>(3)
                };
                DateTimeHelper.GetPeriod(Period.Month, out var mBeginDate, out var mEndDate,
                        DateTime.Now.AddMonths(-1));
                var meterReadings = DistrictMeterRecording(item);
                //按片区统计每个月阶梯用水量
                var meters =  RangeMeterReadingRecord(meterReadings, mBeginDate, mEndDate);
                _owners.ForEach(
                    o => new List<double>
                    {
                       //TODO:逻辑暂未通

            }
                    );
              
                r.list.Add(listItem);
            }
            r.total = r.list.Count.ToString();
            return r;
        }

        /// <summary>
        /// 获取昨日用水统计
        /// </summary>
        /// <returns></returns>
        private YesterdayConsumptionData GetYesterdayConsumptionData()
        {
            ////获取昨日开始，结束时间
            DateTimeHelper.GetPeriod(Period.Day, out var mBeginDate, out var mEndDate,
                DateTime.Now.Date.AddDays(-1));
            var result = new YesterdayConsumptionData
            {
                list = _owners.Select(o => new YesterdayConsumptionListItem
                {
                    ownerId = o.Id.ToString(),
                    houseNumber = o.HouseNumber,
                    waterConsumption =
                        RangeMeterReadingRecord(
                                _meterReadings.Where(r =>
                                    r.ReadTime.Date == mBeginDate.Date && _meters
                                        .Where(m => m.OwnerId == o.Id.ToString())
                                        .Select(m => m.MeterNumber).Contains(r.MeterNumber)).ToList(), mBeginDate,
                                mEndDate)
                            .Sum(l => l.Last().Value - l.First().Value)
                }).ToList()
            };
            result.total = result.list.Count.ToString();
            return result;
        }

        private DistrictReadRatioData GetDistrictReadRatioData()
        {
            throw new NotImplementedException();
        }

        private ClosingvalveData GetClosingvalveData()
        {
            throw new NotImplementedException();
        }

        private CostReminderData GetCostReminderData()
        {
           
            throw new NotImplementedException();
        }

        /// <summary>
        /// 赋值
        /// </summary>
        /// <param name="uid"></param>
        private void SetListValue(string uid)
        {
            //获取操作员信息
            var staff = _repository.FindAllAsNoTracking<StaffEntity>().First(s => s.Id.ToString() == uid);
            _logger.Info($"{staff.Name}开始获取图表页");
            //获取片区
            _districts = _districtRepository.GetFatherNodeDistricts(staff);
            _leafDistricts = _districtRepository.GetLefNodeDistricts(_districts);
            //获取业主
            _owners = _chartRepository.GetOwners(_leafDistricts.Select(l => l.Id.ToString()).ToArray());
            //获取账户
            _accounts = _chartRepository.GetAccounts(_owners.Select(o => o.Id.ToString()).ToArray());
            //获取水表
            _meters = _chartRepository.GetMeters(_owners.Select(o => o.Id.ToString()).ToArray());
            //获取抄表记录
            _meterReadings = _chartRepository.GetMeterReadings(_meters.Select(m => m.MeterNumber).ToArray());
        }

        private List<MeterReadingRecord> DistrictMeterRecording(DistrictEntity district)
        {
            var districts = _leafDistricts.Where(l => l.Parent == district.Id.ToString()).Select(l=>l.Id.ToString());
            var owners = _owners.Where(o => districts.Contains(o.DistrictId)).Select(o=>o.Id.ToString());
            var meters = _meters.Where(m=> owners.Contains(m.OwnerId)).Select(o => o.MeterNumber);
            return _meterReadings.Where(m => meters.Contains(m.MeterNumber)).ToList();
        }

        /// <summary>
        /// 获取一定时间范围内各水表的最早抄表记录和最后抄表记录
        /// </summary>
        /// <param name="records"></param>
        /// <param name="sDateTime"></param>
        /// <param name="eDateTime"></param>
        /// <returns></returns>
        private List<List<MeterReadingRecord>> RangeMeterReadingRecord(List<MeterReadingRecord> records,
            DateTime sDateTime, DateTime eDateTime)
        {
            //获取离开始时间最近的抄表记录
            var starList = _meterReadings
                .Where(m => m.ReadTime >= sDateTime)
                .OrderBy(r => r.MeterNumber).ThenBy(r => r.ReadTime)
                .GroupBy(r => r.MeterNumber).Select(v => v.First());
            //获取离结束时间最近的抄表记录
            var endList = _meterReadings
                .Where(m => m.ReadTime <= eDateTime)
                .OrderBy(r => r.MeterNumber).ThenByDescending(r => r.ReadTime)
                .GroupBy(r => r.MeterNumber).Select(v => v.First());
            var result = starList.Select(s => new List<MeterReadingRecord>
            {
                s,
                endList.First(e => e.MeterNumber == s.MeterNumber)
            }).ToList();
            return result;
        }
    }
}